package com.atguigu.es.demo;

import com.atguigu.es.demo.bean.Goods;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SpringBootTest
public class EsDemoTest2 {
    @Resource
    ElasticsearchRestTemplate restTemplate;
    /*
     查询有货的小米手机前五条记录，
    标题关键字高亮显示，按照价格排序，只需要标题价格图片属性。
    并查询品牌桶，品牌桶内嵌套分类桶，统计每个分类的平均价格。

    # 1、匹配查询：小米手机
    # 2、范围查询：stoke>0 有货
    # 3、分页查询： 前五条记录
    # 4、高亮查询： 标题高亮
    # 5、排序：价格排序
    # 6、结果过滤： 只查询文档的指定字段
    # 7、聚合查询： 查询品牌 和分类桶
     */
    @Test
    void test1(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //query的内容
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //设置bool查询中的查询条件
        boolQuery.must(QueryBuilders.matchQuery("title","小米手机"));
        boolQuery.filter(QueryBuilders.rangeQuery("stock")
                        .gt(0));
        //排序:价格降序排列
        builder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        //分页
        builder.withPageable(PageRequest.of(0,5));//page表示查询数据的起始索引 ， size：查询记录条数
        builder.withQuery(boolQuery);
        //高亮
        builder.withHighlightBuilder(new HighlightBuilder().field("title")
                        .preTags("<font style='color:red;'>")
                        .postTags("</font>"));
        //结果字段过滤
        builder.withSourceFilter(new FetchSourceFilter(new String[]{"title","price","id",
            "attr.brand","attr.category"},new String[]{}));


        //  # 7、聚合查询： 查询品牌桶，品牌桶内嵌套分类桶，统计每个分类的平均价格
        builder.addAggregation(AggregationBuilders
            .terms("品牌")//桶名
            .field("attr.brand.keyword") //指定划分桶的字段
                .subAggregation(AggregationBuilders//桶内嵌套桶
                        .terms("分类")
                        .field("attr.category.keyword")
                    .subAggregation(AggregationBuilders
                                .avg("平均价格")
                                .field("price")
                    )
                )
            );


        //query代表查询时 dsl 的json条件
        NativeSearchQuery query = builder.build();//使用builder对象的配置构建DSL的json条件
        System.out.println("DSL: " +query);
        //执行查询
        SearchHits<Goods> searchHits = restTemplate.search(query, Goods.class,
                IndexCoordinates.of("atguigu"));

        //解析结果：
        long totalHits = searchHits.getTotalHits();
        System.out.println("查询到的文档数量："+ totalHits);
        //1、得到hits结果集
        List<SearchHit<Goods>> hits = searchHits.getSearchHits();
        List<Goods> list = new ArrayList<>();
        //2、遍历结果集 获取每一个文档内容
        hits.forEach(hit->{
            Goods goods = hit.getContent();
            System.out.println("解析到的文档："+ goods);
           // Map<String, List<String>> highlightFields = hit.getHighlightFields();
            List<String> highlightField = hit.getHighlightField("title");
            System.out.println("高亮字段："+ highlightField);

            //将高亮字段字符串设置给goods的标题属性
            goods.setTitle(StringUtils.join(highlightField , ""));
//            hit.getSortValues();
            list.add(goods);
        });

        System.out.println("查询到的文档内容："+ list);

        //解析聚合结果
        //聚合映射： 桶名-> 聚合结果
        Map<String, Aggregation> map = searchHits.getAggregations().asMap();
        ParsedStringTerms agg = (ParsedStringTerms) map.get("品牌");
        //获取品牌聚合结果对象 真实类型
//        System.out.println(agg.getClass().getName());
        List<? extends Terms.Bucket> buckets = agg.getBuckets();
        buckets.forEach(bucket->{
            System.out.println("bucketName ： "+ bucket.getKey());
            System.out.println("count ： "+bucket.getDocCount());
            //获取bucket的子桶
            ParsedStringTerms agg2 = (ParsedStringTerms) bucket.getAggregations().asMap().get("分类");
            agg2.getBuckets().forEach(bucket2->{
                System.out.println("bucket2Name ： "+ bucket2.getKey());
                System.out.println("count2 ： "+bucket2.getDocCount());
                //获取bucket2的度量结果
                ParsedAvg agg3 = (ParsedAvg) bucket2.getAggregations().asMap().get("平均价格");
//                System.out.println(agg3.getClass().getName());
                System.out.println("类型： "+agg3.getType());
                System.out.println("值："+ agg3.getValue());
            });
        });


    }
}
